package com.framework.buss.bridge.service.impl;

import com.framework.buss.bridge.constant.BussConstant;
import com.framework.buss.bridge.em.DataFromEnum;
import com.framework.buss.bridge.em.DataTypeEnum;
import com.framework.buss.bridge.model.BridgeTemplate;
import com.framework.buss.bridge.mapper.BridgeTemplateMapper;
import com.framework.buss.bridge.service.IBridgeTemplateFileService;
import com.framework.buss.bridge.service.IBridgeTemplateService;
import com.framework.buss.bridge.service.IBridgeValueService;
import com.framework.buss.bridge.vo.BridgeTemplateVO;
import com.framework.buss.bridge.vo.UploadVO;
import com.framework.common.domain.ResultData;
import com.framework.common.util.CommonUtils;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hwpf.HWPFDocument;
import org.apache.poi.hwpf.extractor.WordExtractor;
import org.apache.poi.hwpf.usermodel.*;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.LinkedTransferQueue;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Service
@Log4j2
public class BridgeTemplateServiceImpl implements IBridgeTemplateService {
    @Value("${path.temp:/data}")
    private String path;

    @Autowired
    private IBridgeValueService bridgeValueService;
    @Autowired
    private BridgeTemplateMapper templateMapper;
    @Autowired
    private IBridgeTemplateFileService bridgeTemplateFileService;

    @Override
    public BridgeTemplate getById(String id) {
        return templateMapper.getById(id);
    }

    @Override
    public void saveAll(List<BridgeTemplateVO> list, String bridgeId, String filePath) {
        if (list.size() == 0) {
            return;
        }
        List<BridgeTemplateVO> saveList = new ArrayList<>();

        LinkedTransferQueue<BridgeTemplateVO> queue = new LinkedTransferQueue();
        list.forEach(it -> {
            queue.add(it);
        });

        long sort = 0L;
        while (!queue.isEmpty()) {
            BridgeTemplateVO vo = queue.poll();
            vo.setBridgeId(bridgeId);
            vo.setSort(sort++);
            if (StringUtils.isBlank(vo.getDataFrom())) {
                vo.setDataFrom(DataFromEnum.TABLE.code);
            }
            if (StringUtils.isBlank(vo.getType())) {
                vo.setType(DataTypeEnum.STRING.code);
            }
            if (StringUtils.isBlank(vo.getSourceTable())) {
                vo.setSourceTable(BussConstant.defaultTable);
            }
            saveList.add(vo);
            List<BridgeTemplateVO> children = vo.getChildren();
            if (null != children && children.size() >0) {
                children.forEach(it -> {
                    queue.add(it);
                });
                vo.setLeaf(false);
            } else {
                vo.setLeaf(true);
            }
        }
        templateMapper.deleteByBridgeId(bridgeId);
        templateMapper.insertAll(saveList);
        bridgeValueService.insertAll(saveList);

        bridgeTemplateFileService.saveFile(bridgeId, filePath);
    }

    @Override
    public List<BridgeTemplateVO> listAll(BridgeTemplate bridgeTemplate) {
        List<BridgeTemplateVO> list = templateMapper.findAll(bridgeTemplate);
        List<BridgeTemplateVO> tree = getChildren(list, StringUtils.EMPTY);
        return tree;
    }

    private List<BridgeTemplateVO> getChildren(List<BridgeTemplateVO> allList, String pid) {
        List<BridgeTemplateVO> tree = allList.stream()
                .filter(it-> {
                    if (null == it.getPid()) {
                        it.setPid(StringUtils.EMPTY);
                    }
                    return it.getPid().equals(pid);
                }).collect(Collectors.toList());

        tree.forEach(it -> it.setChildren(getChildren(allList, it.getId())));
        return tree;
    }

    @Override
    public void save(BridgeTemplate bridgeTemplate) {
        templateMapper.insert(bridgeTemplate);
    }

    @Override
    public void updateById(BridgeTemplate bridgeTemplate) {
        templateMapper.updateById(bridgeTemplate);
    }

    @Override
    public void removeById(String id) {
        templateMapper.removeById(id);
    }

    @Override
    public ResultData<?> importSetting(HttpServletRequest request, HttpServletResponse response) {
        MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
        Map<String, MultipartFile> fileMap = multipartRequest.getFileMap();
        for (Map.Entry<String, MultipartFile> entity : fileMap.entrySet()) {
            // 获取上传文件对象
            MultipartFile file = entity.getValue();
            // 上传文件到minio
            String fileId = UUID.randomUUID().toString().replaceAll("_", "");
            String filePath = path.concat("/template/bridge/").concat(fileId);
            filePath = CommonUtils.upload(file, filePath);
            return importItem(file, filePath);
        }
        return ResultData.success("文件导入成功");
    }

    private ResultData<?> importItem(MultipartFile file, String filePath) {
        List<BridgeTemplateVO> treeModelList = new ArrayList<>();
        InputStream is = null;
        try {
            String path = file.getOriginalFilename();
            is = file.getInputStream();
            StringBuffer buffer = new StringBuffer();
            if (path.endsWith(".doc")) {
                WordExtractor extractor = new WordExtractor(is);
                String[] paragraphText = extractor.getParagraphText();   // 获取段落，段落缩进无法获取，可以在前添加空格填充
                if (null == paragraphText || paragraphText.length == 0) {
                    return ResultData.error("文件没有内容！");
                }
                for (String paragraph : paragraphText) {
                    buffer.append(paragraph);
                }
                List<BridgeTemplateVO> itemList = getTree(buffer, 1);
                treeModelList.addAll(itemList);
                buffer.setLength(0);
                readTable(is, buffer);
                itemList = getTree(buffer, 2);
                treeModelList.addAll(itemList);
                extractor.close();
            } else if (path.endsWith(".docx")) {
                XWPFDocument document = new XWPFDocument(is);
                List<XWPFParagraph> paragraphs = document.getParagraphs();
                if (null == paragraphs || paragraphs.size() == 0) {
                    return ResultData.error("文件没有内容！");
                }
                for (XWPFParagraph paragraph : paragraphs) {
                    buffer.append(paragraph.getParagraphText());
                }
                List<BridgeTemplateVO> itemList = getTree(buffer, 1);
                treeModelList.addAll(itemList);
                buffer.setLength(0);
                readTable(document, buffer);
                itemList = getTree(buffer, 2);
                treeModelList.addAll(itemList);
            } else {
                return ResultData.error("文件格式错误！");
            }
            UploadVO uploadVO = new UploadVO(treeModelList, filePath);
            return ResultData.data(uploadVO);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return ResultData.error("文件导入失败！");
        } finally {
            if (null != is) {
                try {
                    is.close();
                } catch (IOException e) {
                    log.error(e.getMessage());
                }
            }
        }
    }

    private void readTable(InputStream is, StringBuffer buffer) throws IOException {
        HWPFDocument doc = new HWPFDocument(is);
        Range r = doc.getRange();
        TableIterator it = new TableIterator(r);
        while (it.hasNext()) {
            Table tb = it.next();
            for (int i = 0; i < tb.numRows(); i++) {
                TableRow tr = tb.getRow(i);  // 获取行
                for (int j = 0; j < tr.numCells(); j++) {
                    TableCell td = tr.getCell(j);//取得单元格
                    for (int k = 0; k < td.numParagraphs(); k++) {
                        Paragraph para = td.getParagraph(k); // 段落
                        String text = para.text(); // 获取内容
                        buffer.append(text);
                    }
                }
            }
        }
    }

    private void readTable(XWPFDocument document, StringBuffer buffer) {
        List<XWPFTable> tables = document.getTables();
        tables.forEach(it -> {
            buffer.append(it.getText());
        });
    }

    // 模板循环以{{?xxx}}{{/xxx}}标签为分界  表格循环 以[]表示子级
    private List<BridgeTemplateVO> getTree(StringBuffer buffer, int type) {
        List<BridgeTemplateVO> tree = new ArrayList<>();
        String strWords = buffer.toString();
        //定义正则
        String regex = "\\{\\{(.*?)\\}\\}|\\[(.*?)\\]"; // \b代表单词的边界
        //将正则封装成对象
        Pattern p = Pattern.compile(regex);
        //将正则对象与要操作的字符串相关联
        Matcher m = p.matcher(strWords);
        //输出
        List<String> keys = new ArrayList<>();
        BridgeTemplateVO parent = null;
        while(m.find()) {
            BridgeTemplateVO treeModel = new BridgeTemplateVO();
            String group = m.group(1);
            // 第二个匹配是子级
            if (StringUtils.isBlank(group)) {
                // 不是表格不添加
                if (type == 1) {
                    continue;
                }
                group = m.group(2);
                BridgeTemplateVO last = tree.get(tree.size()-1);
                last.setLeaf(false);
                last.setType(DataTypeEnum.TABLE.code);
                List<BridgeTemplateVO> children = last.getChildren();
                // 加入上级
                if (null == children) {
                    children = new ArrayList<>();
                    last.setChildren(children);
                }
                treeModel.setPid(last.getId());
                children.add(treeModel);
            } else {
                // 第一个层级需要判断变量不可重复
                if (keys.contains(group)) {
                    continue;
                }
                if (null == parent) {
                    keys.add(group);
                }
                if (group.startsWith("/")) {
                    parent = null;
                    continue;
                }
                if (group.startsWith("@")) {
                    group = group.substring(1);
                    treeModel.setType(DataTypeEnum.IMAGE.code);
                }
                if (group.startsWith("?")) {
                    group = group.substring(1);
                    treeModel.setLeaf(false);
                    treeModel.setType(DataTypeEnum.LIST.code);
                    List<BridgeTemplateVO> parentChildren = new ArrayList<>();
                    treeModel.setChildren(parentChildren);
                    tree.add(treeModel);
                    parent = treeModel;
                } else {
                    treeModel.setLeaf(true);
                    if (null != parent) {
                        treeModel.setPid(parent.getId());
                        parent.getChildren().add(treeModel);
                    } else {
                        tree.add(treeModel);
                    }
                }
            }
            String id = UUID.randomUUID().toString().replaceAll("-", "");
            treeModel.setTitle(group);
            treeModel.setId(id);
        }
        return tree;
    }
}
